package chapt08.tunnel;
// Tunnel.java
// Demonstrates mipmapping and using texture objects
// OpenGL SuperBible
// Richard S. Wright Jr.

import java.nio.ByteBuffer;
import java.io.IOException;

import javax.media.opengl.GL2;
import javax.media.opengl.glu.gl2.GLUgl2;

import com.jogamp.opengl.util.texture.spi.TGAImage;

public class Tunnel
{
	static GLUgl2 glu = new GLUgl2();
	
	// Rotation amounts
	static float zPos = -60.0f;
	
	// Texture objects
	static int TEXTURE_BRICK = 0;
	static int TEXTURE_FLOOR = 1;
	static int TEXTURE_CEILING = 2;
	static int TEXTURE_COUNT = 3;
	static int textures[] = new int [TEXTURE_COUNT];
	static String szTextureFiles[] = {"brick.tga", "floor.tga", "ceiling.tga"};
	
	static int processMenuValue = 0;
	
	///////////////////////////////////////////////////////////////////////////////
	// Change texture filter for each texture object
	public static void processMenu(GL2 gl2, int value)
	{
		int iLoop;
		
		for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
		{
			gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[iLoop]);
			
			switch(value)
			{
				case 0:
					gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
					break;
			
				case 1:
					gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
					break;
				
				case 2:
					gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST_MIPMAP_NEAREST);
					break;
				
				case 3:
					gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST_MIPMAP_LINEAR);
					break;
					
				case 4:
					gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_NEAREST);
					break;
					
				case 5:
				default:
					gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_LINEAR);
					break;
			}
		}
	}
	
	//////////////////////////////////////////////////////////////////
	// This function does any needed initialization on the rendering
	// context.  Here it sets up and initializes the texture objects.
	protected static void setupRC(GL2 gl2, int width, int height)
	{
		ByteBuffer pBytes;
		int iWidth, iHeight;
		int eFormat;
		int iLoop;
		
		// Black background
		gl2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		
		// Textures applied as decals, no lighting or coloring effects
		gl2.glEnable(GL2.GL_TEXTURE_2D);
		gl2.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_DECAL);
		
		// Load textures
		gl2.glGenTextures(TEXTURE_COUNT, textures, 0);
		for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
		{
			// Bind to next texture object
			gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[iLoop]);
			
			// Load texture, set filter and wrap modes
			try
			{
				TGAImage tgaImage = TGAImage.read(Tunnel.class.getResourceAsStream(szTextureFiles[iLoop]));
				iWidth = tgaImage.getWidth();
				iHeight = tgaImage.getHeight();
				eFormat = tgaImage.getGLFormat();
				pBytes = tgaImage.getData();
				
				// Load texture, set filter and wrap modes
				glu.gluBuild2DMipmaps(GL2.GL_TEXTURE_2D, GL2.GL_RGB, iWidth, iHeight, eFormat, GL2.GL_UNSIGNED_BYTE, pBytes);
				gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
				gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_LINEAR);
				gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
				gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
				
				// Don't need original texture data any more
				pBytes = null;
			}
			catch(IOException e)
			{
				System.exit(0);
			}
		}
	}
	
	///////////////////////////////////////////////////////
	// Called to draw scene
	protected static void renderScene(GL2 gl2, int w, int h)
	{
		processMenu(gl2, processMenuValue);
		
		float z;
		
		// Clear the window with current clearing color
		gl2.glClear(GL2.GL_COLOR_BUFFER_BIT);
		
		// Save the matrix state and do the rotations
		gl2.glPushMatrix();
			// Move object back and do in place rotation
			gl2.glTranslatef(0.0f, 0.0f, zPos);
			
			// Floor
			for(z = 60.0f; z >= 0.0f; z -= 10.0f)
			{
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
				gl2.glBegin(GL2.GL_QUADS);
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(-10.0f, -10.0f, z);
					
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(10.0f, -10.0f, z);
					
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(10.0f, -10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(-10.0f, -10.0f, z - 10.0f);
				gl2.glEnd();
				
				// Ceiling
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
				gl2.glBegin(GL2.GL_QUADS);
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(-10.0f, 10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(10.0f, 10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(10.0f, 10.0f, z);
					
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(-10.0f, 10.0f, z);
				gl2.glEnd();
				
				// Left Wall
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
				gl2.glBegin(GL2.GL_QUADS);
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(-10.0f, -10.0f, z);
					
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(-10.0f, -10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(-10.0f, 10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(-10.0f, 10.0f, z);
				gl2.glEnd();
				
				// Right Wall
				gl2.glBegin(GL2.GL_QUADS);
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(10.0f, 10.0f, z);
					
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(10.0f, 10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(10.0f, -10.0f, z - 10.0f);
					
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(10.0f, -10.0f, z);
				gl2.glEnd();
			}
		
		// Restore the matrix state
		gl2.glPopMatrix();
		
		// Buffer swap
		gl2.glFlush();
	}

	/////////////////////////////////////////////////////////////////////
	// Change viewing volume and viewport.  Called when window is resized
	public static void changeSize(GL2 gl2, int w, int h)
	{
		float fAspect;
		
		// Prevent a divide by zero
		if(h == 0)
			h = 1;
		
		// Set Viewport to window dimensions
		gl2.glViewport(0, 0, w, h);
		
		fAspect = (float)w / (float)h;
		
		// Reset coordinate system
		gl2.glMatrixMode(GL2.GL_PROJECTION);
		gl2.glLoadIdentity();
		
		// Produce the perspective projection
		glu.gluPerspective(90.0f, fAspect, 1, 120);
		
		gl2.glMatrixMode(GL2.GL_MODELVIEW);
		gl2.glLoadIdentity();
	}
}